<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Wxpay extends Model
{
    
    
    
     /**
        * 产生随机字符串，不长于32位
        * @param int $length
        * @return string 产生的随机字符串
     */
    function getNonceStr($length = 32)
    {
                $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
                $str = '';
                for ($i = 0; $i < $length; $i++) {
                    $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
                }
                return $str;
    }
    
    
        /**
        * 将一个数组转换为 XML 结构的字符串
        * @param array $arr 要转换的数组
        * @param int $level 节点层级, 1 为 Root.
        * @return string XML 结构的字符串
        */
       function arraytoXml($arr, $level = 1)
       {
           $s = $level == 1 ? "<xml>" : '';
           foreach ($arr as $tagname => $value) {
               if (is_numeric($tagname)) {
                   $tagname = $value['TagName'];
                   unset($value['TagName']);
               }
               if (!is_array($value)) {
                   $s .= "<{$tagname}>" . (!is_numeric($value) ? '<![CDATA[' : '') . $value . (!is_numeric($value) ? ']]>' : '') . "</{$tagname}>";
               } else {
                   $s .= "<{$tagname}>" . $this->arraytoXml($value, $level + 1) . "</{$tagname}>";
               }
           }
           $s = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", ' ', $s);
           return $level == 1 ? $s . "</xml>" : $s;
       }
       
       
       /**
        * 将xml转为array
        * @param  string $xml xml字符串
        * @return array    转换得到的数组
        */
       function xmltoArray($xml)
       {
           //禁止引用外部xml实体
           libxml_disable_entity_loader(true);
           $result = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
           return $result;
       }
       
       
       /**
        * 生成签名
        * @param $data
        * @return string
        */
       function makeSign($data)
       {
           //获取微信支付秘钥
           $key = config('key');

           //去空
           $data = array_filter($data);

           //签名步骤一：按字典序排序参数
           ksort($data);
           $string_a = http_build_query($data);
           $string_a = urldecode($string_a);

           //签名步骤二：在string后加入KEY
           $string_sign_temp = $string_a . "&key=$key";

           //签名步骤三：MD5加密
           $sign = md5($string_sign_temp);

           //签名步骤四：所有字符转为大写
           return strtoupper($sign);
       }
       
       
           /**
            * 微信支付发起请求
            * @param $url
            * @param $xmldata
            * @param int $second
            * @param array $aHeader
            * @return bool|mixed
            */
           protected function curl_post_ssl($url, $xmldata, $second = 30, $aHeader = array())
           {
               $ch = curl_init();
               //超时时间
               curl_setopt($ch, CURLOPT_TIMEOUT, $second);
               curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
               //这里设置代理，如果有的话
               //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
               //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
               curl_setopt($ch, CURLOPT_URL, $url);
               curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
               curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
               if (count($aHeader) >= 1) {
                   curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
               }
               curl_setopt($ch, CURLOPT_POST, 1);
               curl_setopt($ch, CURLOPT_POSTFIELDS, $xmldata);
               $data = curl_exec($ch);
               if ($data) {
                   curl_close($ch);
                   return $data;
               } else {
                   $error = curl_errno($ch);
                   echo "call faild, errorCode:$error\n";
                   curl_close($ch);
                   return false;
               }
           }
           
           
           
           /**
            * @param $unifiedorder
            * @return array
            * @throws \Exception
            */
           function prepay($unifiedorder)
           {
               $unifiedorder['sign'] = $this->makeSign($unifiedorder);
               $xmldata = $this->arraytoXml($unifiedorder);

               $url = config('pay_url');

               $res = $this->curl_post_ssl($url, $xmldata);
               if (!$res) {
                   throw new \Exception('链接Wechat服务器失败 (ｷ｀ﾟДﾟ´)');
               }

               $content = $this->xmltoArray($res);
               if (strval($content['return_code']) == 'FAIL') {
                   throw new \Exception('生成签名数据失败 (￣□￣;)');
               }

               //拼接小程序的接口数据
               $result = [
                   'appId' => strval($content['appid']),
                   'timeStamp' => time(),
                   'nonceStr' => $this->getNonceStr(),
                   'package' => 'prepay_id=' . strval($content['prepay_id']),
                   'signType' => 'MD5',
               ];

               //加密签名
               $result['paySign'] = $this->makeSign($resData);

               return $result;
           }
           
           
           
           function WeChatOrder(Request $request)
            {
                $code = $request->get('code');

                $payHelper = new WechatHelper();
                $openId = $payHelper->getOpenID($code);

                try {
                    DB::beginTransaction();

                    //生成业务订单
                    $order = [
                        'orderNum' => 123456789,
                        'price' => 2333,
                       
                    ];

                    Order::create($order);

                    $unifiedorder = [
                        'openid' => $openId,
                        'appid' => config('miniapp_id'),
                        'mch_id' => config('mch_id'),
                        'nonce_str' => $payHelper->getNonceStr(),//获取随机字符串
                        'body' => '商品讯息',
                        'out_trade_no' => $order['orderNum'],
                        'total_fee' => $order['price'],//单位为"分"
                        'spbill_create_ip' => $request->ip(),
                        'notify_url' => config('notify_url'),
                        'trade_type' => 'JSAPI',//小程序均为"JSAPI"
                    ];

                    //再次签名返回
                    $signature = $payHelper->prepay($unifiedorder);

                    DB::commit();
                } catch (QueryException $e) {
                    DB::rollback();
                    throw new \Exception('提交订单失败 T^T');
                } catch (\Exception $e) {
                    DB::rollback();
                    throw new \Exception('出错了 T^T');
                }

                //返回$signature给前端

            }



    
}
